#!/bin/bash
###
 # @file            cli-checker.sh
 # @author          mening
 # @date            2024-08-16 16:36:52
 # @copyright       Copyright (c) 2024 by 北京长扬科技有限公司, ALL Rights Reserved.
 # @note            代码规范:
 # 	1.复杂逻辑分全局配置,函数定义,执行逻辑三部分.
 # 	2.全局变量大写下滑线命名.
 # 	3.局部变量小写下滑线命名.
 # 	4.函数大驼峰命名.
 # @details         解析二进制程序调用参数并输出到文件中。
###
###################### 全局变量 #####################
# 待分析的rpm包
RPM_TO_ANALYZED=""
# 脚本执行目录
CMD_PATH="$(pwd)"
# rpm解压的虚拟根目录
CHROOT_DIR="${CMD_PATH}/work-file"
# 指定报告目录
REPORT_DIR="${CMD_PATH}/cli-report"
###################### function-lib #####################

###
 # @brief        检查入参
 # @author       mening
###
function CheckEntry()
{
    if [ -z "$1" ] || [[ ! $1 =~ \.rpm$ ]]
    then
        if [ -z "$1" ]
        then
            echo "[CheckEntry]:检测参数为空."
        elif [[ ! $1 =~ \.rpm$ ]]
        then
            echo "[CheckEntry]:参数校验异常."
        fi
        echo "[CheckEntry]: cli-checker.sh RPM-NAME [REPORT-DIR]"
        echo "[CheckEntry]:     RPM-NAME        待检测rpm包名"
        echo "[CheckEntry]:     REPORT-DIR      指定存放结果文件目录,默认为当前目录下cli-report"
        exit 1
    else
        echo "[CheckEntry]: 待检测rpm包: $1"
        RPM_TO_ANALYZED=$1
    fi

    if [ -z "$2" ]
    then
        echo "[CheckEntry]: 结果输出目录: ${REPORT_DIR}"
    else
        echo "[CheckEntry]: 结果输出目录: $2"
        REPORT_DIR=$2
        RPM_TO_ANALYZED=${REPORT_DIR}/${RPM_TO_ANALYZED}
    fi

    if [ ! -d "${REPORT_DIR}" ]
    then
        mkdir -p "${REPORT_DIR}"
    fi

    if [ ! -f "${RPM_TO_ANALYZED}" ]
    then
        echo "[CheckEntry]:未找到待检测rpm包: ${RPM_TO_ANALYZED} ."
        exit 1
    fi

    return 0
}

###
 # @brief        解压目标rpm包到指定目录
 # @author       mening
###
function DecompressingPackages()
{
    if [ -d "${CHROOT_DIR}" ]
    then
        echo "[DecompressingPackages]:发现临时解压目录已存在: ${CHROOT_DIR}."
    else
        echo "[DecompressingPackages]:创建临时解压目录: ${CHROOT_DIR}."
        mkdir -p "${CHROOT_DIR}"
    fi

    rm -rf "${CHROOT_DIR:?}/*"

    local rpm_name
    # 分离目录和文件名
    rpm_name=${RPM_TO_ANALYZED##*\/}

    cp -rfp "${RPM_TO_ANALYZED}" "${CHROOT_DIR}"
    cd "${CHROOT_DIR}" || return 1
    rpm2cpio "${rpm_name}" | cpio -di
    return 0
}

###
 # @brief        遍历所有二进制文件获取帮助信息
 # @author       mening
###
function CheckCliInformation()
{
    echo "[CheckCliInformation]:临时加载虚拟根目录lib路径到进程环境变量."
    local lib_dir
    local sbin_dir
    local bin_dir
    lib_dir="usr/lib64"
    sbin_dir="usr/sbin"
    bin_dir="usr/bin"
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"${CHROOT_DIR}/${lib_dir}"

    cd "${CHROOT_DIR}/../" || return 1

    # 遍历虚拟根目录的bin,sbin下文件,并尝试输出帮助信息,并记录
    for dir in "${sbin_dir}" "${bin_dir}"
    do
        if [ ! -d "${CHROOT_DIR}/${dir}" ]
        then
            continue
        fi

        for full_name in "work-file/${dir}"/*
        do
            #echo "[debug][CheckCliInformation]:检索目标文件: ${full_name}."
            [ -e "${full_name}" ] || break
            file_name=${full_name##*\/}
            #echo "[debug][CheckCliInformation]:截取文件名: ${file_name}."
            if file "${full_name}" | grep executable > /dev/null 2>&1
            then
                if "${full_name}" --help > /dev/null 2>&1
                then
                    "${full_name}" --help > "${REPORT_DIR}/${file_name}-cli.report"
                elif "${full_name}" -help > /dev/null 2>&1
                then
                    "${full_name}" -help > "${REPORT_DIR}/${file_name}-cli.report"
                elif "${full_name}" help > /dev/null 2>&1
                then
                    "${full_name}" help > "${REPORT_DIR}/${file_name}-cli.report"
                elif "${full_name}" -h > /dev/null 2>&1
                then
                    "${full_name}" -h > "${REPORT_DIR}/${file_name}-cli.report"
                fi
            fi
        done
    done

    # 更改生成的文件，因为会记录里面的路径为虚拟根目录，需要将其去除
    for report_file in "${REPORT_DIR}"/*-cli.report
    do
        if grep "^work-file" "${report_file}" > /dev/null
        then
            sed -e 's/^work-file//g' "${report_file}" > "${report_file}".new
            mv "${report_file}".new "${report_file}"
        fi
    done
}

###
 # @brief        安装待测rpm包系统环境中
 # @author       mening
###
function InstallPackage()
{
    echo "[InstallPackage]:安装${RPM_TO_ANALYZED}到系统环境中."
    dnf install -y "${RPM_TO_ANALYZED}"
}

###
 # @brief        遍历rpm内二进制文件获取帮助信息
 # @author       mening
###
function GetCliInformation()
{
    local file_list=""
    local file_name
    local rpm_name
    local pack_name
    pack_name=${RPM_TO_ANALYZED##*\/}
    rpm_name=${pack_name%\.rpm*}
    file_list=$(rpm -ql "${rpm_name}" | grep -E "^/usr/s?bin")
    if [ -n "${file_list}" ]
    then
        while IFS= read -r line
        do
            file_name=${line##*\/}
            if file "${line}" | grep executable > /dev/null 2>&1
            then
                if "${line}" --help > /dev/null 2>&1
                then
                    "${line}" --help > "${REPORT_DIR}/${file_name}-cli.report"
                elif "${line}" -help > /dev/null 2>&1
                then
                    "${line}" -help > "${REPORT_DIR}/${file_name}-cli.report"
                elif "${line}" help > /dev/null 2>&1
                then
                    "${line}" help > "${REPORT_DIR}/${file_name}-cli.report"
                elif "${line}" -h > /dev/null 2>&1
                then
                    "${line}" -h > "${REPORT_DIR}/${file_name}-cli.report"
                else
                    echo "${line}" >> "${REPORT_DIR}/Unaided-program.list"
                fi
            fi
        done <<< "${file_list}"
    fi
}
###################### Main #####################
# 检查入参
CheckEntry "$@"
# 解压目标rpm包(废弃)
#DecompressingPackages
# 安装rpm包到系统环境
InstallPackage
# 遍历所有二进制文件获取帮助信息
#CheckCliInformation
# 遍历待测软件包内二进制文件获取帮助信息
GetCliInformation